package com.competition.web.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.competition.web.entity.Region;
import com.competition.web.entity.UmsAdmin;
import com.competition.web.entity.UmsAdminExample;
import com.competition.web.entity.UmsAdminLoginLog;
import com.competition.web.entity.UmsAdminRoleRelation;
import com.competition.web.entity.UmsAdminRoleRelationExample;
import com.competition.web.entity.UmsResource;
import com.dao.base.IBaseMapper;
import com.page.PageResponseData;
import com.security.admin.security.util.JwtTokenUtil;
import com.security.admin.security.util.SpringUtil;
import com.competition.web.admin.bo.AdminUserDetails;
import com.competition.web.admin.dao.UmsAdminRoleRelationDao;
import com.competition.web.admin.dto.UmsAdminParam;
import com.competition.web.admin.dto.UpdateAdminPasswordParam;
import com.competition.web.admin.mapper.UmsAdminLoginLogMapper;
import com.competition.web.admin.mapper.UmsAdminMapper;
import com.competition.web.admin.mapper.UmsAdminRoleRelationMapper;
import com.competition.web.admin.service.UmsAdminCacheService;
import com.competition.web.admin.service.UmsAdminService;
import com.basic.service.impl.BaseServiceImpl;
import com.competition.web.admin.util.RequestUtil;
import com.competition.web.constant.Const;
import com.competition.web.constant.RedisConstant;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 后台用户管理Service实现类 Created by macro on 2018/4/26.
 */
@Service
public class UmsAdminServiceImpl extends BaseServiceImpl<UmsAdmin> implements UmsAdminService {
	

	private static final Logger LOGGER = LoggerFactory.getLogger(UmsAdminServiceImpl.class);
	@Autowired
	private JwtTokenUtil jwtTokenUtil;
	@Autowired
	private PasswordEncoder passwordEncoder;
	@Autowired
	private UmsAdminMapper adminMapper;
	@Autowired
	private UmsAdminRoleRelationMapper adminRoleRelationMapper;
	@Autowired
	private UmsAdminRoleRelationDao adminRoleRelationDao;
	@Autowired
	private UmsAdminLoginLogMapper loginLogMapper;

	/**
	 * redis
	 */
	private RedisTemplate<String, List<UmsAdmin>> redisTemplate;
	
	
	public UmsAdminServiceImpl(UmsAdminMapper mapper) {
		super(mapper);
		// TODO Auto-generated constructor stub
	}
	
	@Override
	public UmsAdmin getAdminByUsername(String username) {
		UmsAdmin admin = getCacheService().getAdmin(username);
		if (admin != null)
			return admin;
		UmsAdminExample example = new UmsAdminExample();
		example.createCriteria().andUsernameEqualTo(username);
		List<UmsAdmin> adminList = adminMapper.selectByExample(example);
		if (adminList != null && adminList.size() > 0) {
			admin = adminList.get(0);
			getCacheService().setAdmin(admin);
			return admin;
		}
		return null;
	}

	@Override
	public UmsAdmin register(UmsAdminParam umsAdminParam) {
		UmsAdmin umsAdmin = new UmsAdmin();
		BeanUtils.copyProperties(umsAdminParam, umsAdmin);
		umsAdmin.setCreateTime(new Date());
		umsAdmin.setStatus(1);
		// 查询是否有相同用户名的用户
		UmsAdminExample example = new UmsAdminExample();
		example.createCriteria().andUsernameEqualTo(umsAdmin.getUsername());
		List<UmsAdmin> umsAdminList = adminMapper.selectByExample(example);
		if (umsAdminList.size() > 0) {
			return null;
		}
		// 将密码进行加密操作
		String encodePassword = passwordEncoder.encode(umsAdmin.getPassword());
		umsAdmin.setPassword(encodePassword);
		adminMapper.insert(umsAdmin);
		return umsAdmin;
	}

	@Override
	public String login(String username, String password) {
		String token = null;
		// 密码需要客户端加密后传递
		try {
			UserDetails userDetails = loadUserByUsername(username);

//			LOGGER.debug("password: {}", passwordEncoder.encode(password));
//
//			LOGGER.debug("db->password: {}", userDetails.getPassword());
            if(!passwordEncoder.matches(password,userDetails.getPassword())){
               throw new Error("密码不正确");
            }

			if (!userDetails.isEnabled()) {
				throw new Error("帐号已被禁用");
			}
			UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
					null, userDetails.getAuthorities());
			SecurityContextHolder.getContext().setAuthentication(authentication);
			SecurityContextHolder.getContext().setAuthentication(authentication);
			token = jwtTokenUtil.generateToken(userDetails, ((AdminUserDetails)userDetails).getUmsAdmin().getId());
//            updateLoginTimeByUsername(username);
			insertLoginLog(username);
		} catch (AuthenticationException e) {
			LOGGER.warn("登录异常:{}", e.getMessage());
		}
		return token;
	}

	/**
	 * 添加登录记录
	 * 
	 * @param username 用户名
	 */
	private void insertLoginLog(String username) {
		UmsAdmin admin = getAdminByUsername(username);
		if (admin == null)
			return;
		UmsAdminLoginLog loginLog = new UmsAdminLoginLog();
		loginLog.setAdminId(admin.getId());
		loginLog.setCreateTime(new Date());
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		loginLog.setIp(RequestUtil.getRequestIp(request));
		loginLogMapper.insert(loginLog);
	}

	/**
	 * 根据用户名修改登录时间
	 */
	private void updateLoginTimeByUsername(String username) {
		UmsAdmin record = new UmsAdmin();
		record.setLoginTime(new Date());
		UmsAdminExample example = new UmsAdminExample();
		example.createCriteria().andUsernameEqualTo(username);
		adminMapper.updateByExampleSelective(record, example);
	}

	@Override
	public String refreshToken(String oldToken) {
		return jwtTokenUtil.refreshHeadToken(oldToken);
	}

	@Override
	public UmsAdmin getItem(Long id) {
		return adminMapper.selectByPrimaryKey(id);
	}

	@Override
	public List<UmsAdmin> list(String keyword, Integer pageSize, Integer pageNum) {
		UmsAdminExample example = new UmsAdminExample();
		UmsAdminExample.Criteria criteria = example.createCriteria();
		if (!StrUtil.isEmpty(keyword)) {
			criteria.andUsernameLike("%" + keyword + "%");
			example.or(example.createCriteria().andNickNameLike("%" + keyword + "%"));
		}
		return adminMapper.selectByExample(example);
	}

	@Override
	public int update(Long id, UmsAdmin admin) {
		admin.setId(id);
		UmsAdmin rawAdmin = adminMapper.selectByPrimaryKey(id);
		if (rawAdmin.getPassword().equals(admin.getPassword())) {
			// 与原加密密码相同的不需要修改
			admin.setPassword(null);
		} else {
			// 与原加密密码不同的需要加密修改
			if (StrUtil.isEmpty(admin.getPassword())) {
				admin.setPassword(null);
			} else {
				admin.setPassword(passwordEncoder.encode(admin.getPassword()));
			}
		}
		int count = adminMapper.updateByPrimaryKeySelective(admin);
		getCacheService().delAdmin(id);
		return count;
	}

	@Override
	public int delete(Long id) {
		getCacheService().delAdmin(id);
		int count = adminMapper.deleteByPrimaryKey(id);
		getCacheService().delResourceList(id);
		return count;
	}

	@Override
	public int updateRole(Long adminId, List<Long> roleIds) {
		int count = roleIds == null ? 0 : roleIds.size();
		// 先删除原来的关系
		UmsAdminRoleRelationExample adminRoleRelationExample = new UmsAdminRoleRelationExample();
		adminRoleRelationExample.createCriteria().andAdminIdEqualTo(adminId);
		adminRoleRelationMapper.deleteByExample(adminRoleRelationExample);
		// 建立新关系
		if (!CollectionUtils.isEmpty(roleIds)) {
			List<UmsAdminRoleRelation> list = new ArrayList<>();
			for (Long roleId : roleIds) {
				UmsAdminRoleRelation roleRelation = new UmsAdminRoleRelation();
				roleRelation.setAdminId(adminId);
				roleRelation.setRoleId(roleId);
				list.add(roleRelation);
			}
			adminRoleRelationDao.insertList(list);
		}
		getCacheService().delResourceList(adminId);
		return count;
	}

	@Override
	public List<UmsResource> getRoleList(Long adminId) {
		return adminRoleRelationDao.getRoleList(adminId);
	}

	@Override
	public List<UmsResource> getResourceList(Long adminId) {
		List<UmsResource> resourceList = getCacheService().getResourceList(adminId);
		if (CollUtil.isNotEmpty(resourceList)) {
			return resourceList;
		}
		resourceList = adminRoleRelationDao.getResourceList(adminId);
		if (CollUtil.isNotEmpty(resourceList)) {
			getCacheService().setResourceList(adminId, resourceList);
		}
		return resourceList;
	}

	@Override
	public int updatePassword(UpdateAdminPasswordParam param) {
		if (StrUtil.isEmpty(param.getUsername()) || StrUtil.isEmpty(param.getOldPassword())
				|| StrUtil.isEmpty(param.getNewPassword())) {
			return -1;
		}
		UmsAdminExample example = new UmsAdminExample();
		example.createCriteria().andUsernameEqualTo(param.getUsername());
		List<UmsAdmin> adminList = adminMapper.selectByExample(example);
		if (CollUtil.isEmpty(adminList)) {
			return -2;
		}
		UmsAdmin umsAdmin = adminList.get(0);
		if (!passwordEncoder.matches(param.getOldPassword(), umsAdmin.getPassword())) {
			return -3;
		}
		umsAdmin.setPassword(passwordEncoder.encode(param.getNewPassword()));
		adminMapper.updateByPrimaryKey(umsAdmin);
		getCacheService().delAdmin(umsAdmin.getId());
		return 1;
	}

	@Override
	public UserDetails loadUserByUsername(String username) {
		// 获取用户信息
		UmsAdmin admin = getAdminByUsername(username);
		if (admin != null) {
			List<UmsResource> resourceList = getResourceList(admin.getId());
			return new AdminUserDetails(admin, resourceList);
		}
		throw new UsernameNotFoundException("用户名或密码错误");
	}

	@Override
	public UmsAdminCacheService getCacheService() {
		return SpringUtil.getBean(UmsAdminCacheService.class);
	}

	@Override
	public PageResponseData<UmsAdmin> getUserListBySearch(String keyword, Integer pageSize, Integer pageNum) {
		int count = adminMapper.getUserCountListBySearch(keyword);
		
		if (0 == count) {
			return new PageResponseData<>(0, new ArrayList<>(0));
		}
		
		return new PageResponseData<>(count, adminMapper.getUserListBySearch(keyword, (pageNum - 1) * pageSize, Const.PAGE_SIZE));
	}

	@Override
	public List<UmsAdmin> getUmsAdminsFromCache(Integer[] adminIds) {
		
		if (0 == adminIds.length) {
			return new ArrayList<UmsAdmin>(0);
		}
		
		String key = RedisConstant.getAdminDataKey(adminIds);
		
		ValueOperations<String, List<UmsAdmin>> valueOperations = redisTemplate.opsForValue();
		
		List<UmsAdmin> configs =   valueOperations.get(key);

		if (null != configs) {
			return configs;
		}

		configs = this.getDataByIds(adminIds);

		if (0 == configs.size()) {
			valueOperations.set(key, configs, 3, TimeUnit.SECONDS);

			return configs;
		}

		valueOperations.set(key, configs, 6, TimeUnit.MINUTES);

		return configs;
	}
	
	
	
	@Resource
	public void setRedisTemplate(RedisTemplate<String, List<UmsAdmin>> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

}
